/**
 *
 */
package info.angelloznicoud.ircdl;

import info.angelloznicoud.ircdl.bean.DownloadManager;
import info.angelloznicoud.ircdl.bean.FileManager;
import info.angelloznicoud.ircdl.exception.EmptyDownloadDirectoryException;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Date;
import java.util.Properties;

import org.apache.log4j.Logger;

/**
 * Main class for IrcDownloaderBot.
 *
 * @author ANGELLOZ-NICOUD Sébastien
 * @version 1.0
 */
public class IrcBotDownloader {

	private static final int ARGS_NUM = 2;

	private static Logger LOG = Logger.getLogger(IrcBotDownloader.class);

	private File downloadFolder = null;

	private File outputFolder = null;

	private Properties properties = null;

	private static boolean SIG_INT_RECEIVED = false;

	/**
	 * Main program.
	 *
	 * Args values are :
	 * <ul>
	 * 	<li>args[0] : path to input folder containing download information files.
	 * 	<li>args[1] : path to output folder, where downloads will be saved.
	 * </ul>
	 *
	 * Exit code can be :
	 * <ul>
	 * 	<li>1 : invalid number of arguments.</li>
	 *  <li>2 : input folder is invalid.</li>
	 *  <li>3 : output folder is invalid.</li>
	 *  <li>10 : not file was found in the input folder.</li>
	 *  <li>50 : error(s) while loading properties file.</li>
	 * </ul>
	 * @param args - args values
	 */
	@SuppressWarnings("restriction")
	public static void main(String[] args) {
		if (args.length < ARGS_NUM) {
			LOG.error("Invalid args number.");
			LOG.error("Usage : $0 <input_folder> <output_folder>");
			System.exit(1);
		}

		IrcBotDownloader prog = new IrcBotDownloader();

		prog.check(args);

		//Trying to deals with ^C termination.
		sun.misc.Signal.handle(new sun.misc.Signal("INT"), new sun.misc.SignalHandler(){

			@Override
			public void handle(sun.misc.Signal arg0) {
				LOG.warn("Control+C received. Trying to gracefully exit the program.");
				SIG_INT_RECEIVED = true;
			}

		});

		try {
			prog.loadProperties();
			prog.run();
		} catch (EmptyDownloadDirectoryException e) {
			LOG.error("The folder " + e.getDirectoryName() + " is empty.");
			System.exit(10);
		} catch (FileNotFoundException e) {
			LOG.error("Error while loading properties.", e);
			System.exit(50);
		} catch (IOException e) {
			LOG.error("Error while loading properties.", e);
			System.exit(50);
		}

		System.exit(0);
	}

	/**
	 * Check program arguments.
	 *
	 * @param args - the program arguments.
	 */
	private void check(String[] args) {
		this.downloadFolder = new File(args[0]);
		this.outputFolder   = new File(args[1]);

		if (!this.downloadFolder.exists() || !this.downloadFolder.isDirectory()) {
			LOG.error("Download folder (" + this.downloadFolder.getAbsolutePath() + ") is invalid !");
			System.exit(2);
		}

		if (!this.outputFolder.exists() || !this.outputFolder.isDirectory()) {
			LOG.error("Output folder (" + this.outputFolder.getAbsolutePath() + ") is invalid !");
			System.exit(3);
		}
	}

	/**
	 * Main method. Run the program.
	 *
	 * @throws EmptyDownloadDirectoryException if the folder supposed to contains
	 * download files is empty.
	 *
	 * @throws IOException when an I/O error occurs.
	 */
	private void run() throws EmptyDownloadDirectoryException, IOException {
		LOG.info("Start program : " + new Date().toString());
		LOG.info("=> input folder  : " + this.downloadFolder.getAbsolutePath());
		LOG.info("=> output folder : " + this.outputFolder.getAbsolutePath());

		FileManager fileManager = new FileManager(this.downloadFolder);
		DownloadManager downloadManager =
				new DownloadManager(fileManager,
						Long.parseLong(this.properties.getProperty("refresh.delay")),
						getBotNames(),
						this.outputFolder,
						Boolean.parseBoolean(this.properties.getProperty("bot.verbose")),
						Integer.parseInt(this.properties.getProperty("download.max")));

		Thread downloadThread = new Thread(downloadManager);
		downloadThread.start();

		while (downloadThread.isAlive()) {
			//Print download status.
			String[] currentDownloads = downloadManager.getCurrentDownloads();

			if (currentDownloads != null && currentDownloads.length > 0) {
				LOG.info("Current download list : ");
				int index = 1;
				for (String currentDl : currentDownloads) {
					if (currentDl != null) {
						LOG.info("[" + index + "] " + currentDl);
						index++;
					}
				}
			}

			if (SIG_INT_RECEIVED) {
				downloadManager.sendSigInt();
			}

			try {
				Thread.sleep(Long.parseLong(this.properties.getProperty("refresh.delay")));
			} catch (InterruptedException e) {
				LOG.warn("InterruptedException : ", e);
			}
		}

		LOG.info("No more files to download. Ending program.");

		LOG.info("Quit program : " + new Date().toString());
	}

	/**
	 * Load properties file.
	 *
	 * @throws FileNotFoundException if the properties file is not found.
	 *
	 * @throws IOException in case of I/O errors during properties file reading.
	 */
	private void loadProperties() throws FileNotFoundException, IOException {
		File propertiesFile = new File(System.getProperty("PROPERTY_FILE"));

		this.properties = new Properties();
		this.properties.load(new FileInputStream(propertiesFile));
	}

	/**
	 * Get all bot names.
	 *
	 * @return an array of all possible bot names.
	 */
	private String[] getBotNames() {
		return new String[] { this.properties.getProperty("login.main"),
				this.properties.getProperty("login.alternate.1"),
				this.properties.getProperty("login.alternate.2") };
	}

}
